/**
 * customer服务实现
 *
 * @author sxf
 * @email sxf02615@163.com
 * @date 2025/1/15
 */
package com.sxf.crm.service.impl;


import com.sxf.crm.dto.CustomerDepartmentDTO;
import com.sxf.crm.dto.CustomerDTO;
import com.sxf.crm.entity.Customer;
import com.sxf.crm.entity.CustomerDepartment;
import com.sxf.crm.entity.CustomerDepartmentId;
import com.sxf.crm.entity.Department;
import com.sxf.crm.entity.User;
import com.sxf.crm.enums.CustomerSource;
import com.sxf.crm.enums.CustomerStatus;
import com.sxf.crm.enums.CustomerStage;
import com.sxf.crm.exception.ResourceNotFoundException;
import com.sxf.crm.repository.CustomerRepository;
import com.sxf.crm.repository.CustomerDepartmentRepository;
import com.sxf.crm.repository.DepartmentRepository;
import com.sxf.crm.repository.UserRepository;
import com.sxf.crm.service.CustomerService;
import com.sxf.crm.service.CustomerLogService;
import com.sxf.crm.service.DepartmentService;
import com.sxf.crm.service.UserService;
import com.sxf.crm.util.SecurityUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Implementation of CustomerService providing business logic for customer management.
 * Handles CRUD operations, department associations, and approval workflows.
 */
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class CustomerServiceImpl implements CustomerService {

    private final CustomerRepository customerRepository;
    private final DepartmentRepository departmentRepository;
    private final UserRepository userRepository;
    private final DepartmentService departmentService;
    private final CustomerDepartmentRepository customerDepartmentRepository;
    private final CustomerLogService customerLogService;
    private final UserService userService;

    @Override
    @Transactional(readOnly = true)
    public Page<CustomerDTO> getCustomers(String name, CustomerStage stage, String source, String status, Pageable pageable) {
        CustomerStatus customerStatus = null;
        if (status != null && !status.isEmpty()) {
            try {
                customerStatus = CustomerStatus.valueOf(status);
            } catch (IllegalArgumentException e) {
                log.warn("Invalid customer status: {}", status);
            }
        }

        CustomerSource customerSource = null;
        if (source != null && !source.isEmpty()) {
            try {
                customerSource = CustomerSource.valueOf(source);
            } catch (IllegalArgumentException e) {
                log.warn("Invalid customer source: {}", source);
            }
        }

        Page<Customer> customers = customerRepository.findByNameContainingAndStageAndSourceAndStatus(
            name, stage, customerSource, customerStatus, pageable);
        return customers.map(this::convertToDTO);
    }

    @Override
    public CustomerDTO getCustomer(Long id) {
        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + id));
        return convertToDTO(customer);
    }

    @Override
    @Transactional
    public CustomerDTO createCustomer(CustomerDTO customerDTO) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Customer customer = new Customer();
        BeanUtils.copyProperties(customerDTO, customer);
        customer.setStatus(CustomerStatus.PENDING);
        customer.setCreateAt(System.currentTimeMillis());
        customer.setCreateUserId(currentUserId);
        
        customer = customerRepository.save(customer);
        
        // 记录创建日志
        User operator = userService.getUserById(currentUserId);
        customerLogService.logCreate(customer, operator);
        
        return convertToDTO(customer);
    }

    @Override
    @Transactional
    public CustomerDTO updateCustomer(Long id, CustomerDTO customerDTO) {
        Long currentUserId = SecurityUtils.getCurrentUserId();

        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + id));
        
        String statusBefore = customer.getStatus().name();
        updateCustomerFromDTO(customer, customerDTO);
        
        customer.setUpdateAt(System.currentTimeMillis());
        customer.setUpdateUserId(currentUserId);

        customer = customerRepository.save(customer);
        
        // 记录更新日志
        User operator = userService.getUserById(currentUserId);
        customerLogService.logUpdate(customer, operator, "更新客户基本信息");
        
        // 如果状态发生变化，记录状态变更日志
        if (!statusBefore.equals(customer.getStatus().name())) {
            customerLogService.logStatusChange(customer, operator, statusBefore, customer.getStatus().name());
        }

        return convertToDTO(customer);
    }

    @Override
    @Transactional
    public void deleteCustomer(Long id) {
        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + id));
            
        Long currentUserId = SecurityUtils.getCurrentUserId();
        User operator = userService.getUserById(currentUserId);
        
        // 记录删除日志
        customerLogService.logDelete(customer, operator);
        
        customerRepository.deleteById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<CustomerDepartmentDTO> getCustomerDepartments(Long customerId) {
        log.info("开始查询客户部门关系，customerId: {}", customerId);
        
        List<CustomerDepartment> customerDepartments = customerDepartmentRepository.findByCustomerId(customerId);
        
        log.info("查询到客户部门关系数量: {}", customerDepartments.size());
        
        // 检查是否有null对象
        for (int i = 0; i < customerDepartments.size(); i++) {
            CustomerDepartment cd = customerDepartments.get(i);
            if (cd == null) {
                log.warn("发现null对象在索引位置: {}", i);
            } else {
                log.info("索引 {} - customer: {}, department: {}, sales: {}", 
                    i, 
                    cd.getCustomer() != null ? cd.getCustomer().getId() : "null",
                    cd.getDepartment() != null ? cd.getDepartment().getId() : "null",
                    cd.getSales() != null ? cd.getSales().getId() : "null"
                );
            }
        }

        return customerDepartments.stream()
            .filter(cd -> cd != null) // 过滤掉null对象
            .map(cd -> {
                CustomerDepartmentDTO dto = new CustomerDepartmentDTO();
                
                if (cd.getDepartment() != null) {
                    dto.setDepartmentId(cd.getDepartment().getId());
                    
                    // Build full path name
                    StringBuilder fullPath = new StringBuilder();
                    Department current = cd.getDepartment();
                    while (current != null) {
                        if (fullPath.length() > 0) {
                            fullPath.insert(0, " > ");
                        }
                        fullPath.insert(0, current.getName());
                        current = current.getParent();
                    }
                    dto.setDepartmentName(fullPath.toString());
                } else {
                    log.warn("CustomerDepartment的department为null");
                }
                
                if (cd.getSales() != null) {
                    dto.setSalesId(cd.getSales().getId());
                    dto.setSalesName(cd.getSales().getRealName());
                    dto.setSalesUsername(cd.getSales().getUsername());
                }
                
                return dto;
            })
            .collect(Collectors.toList());
    }

    @Override
    public void addCustomerDepartment(Long customerId, Long departmentId, Long salesId) {
        Customer customer = customerRepository.findById(customerId)
            .orElseThrow(() -> new RuntimeException("Customer not found"));
        
        Department department = departmentRepository.findById(departmentId)
            .orElseThrow(() -> new RuntimeException("Department not found"));
        
        User sales = userRepository.findById(salesId)
            .orElseThrow(() -> new RuntimeException("Sales not found"));
        
        Set<User> departmentUsers = departmentService.getDepartmentAndChildrenUsers(departmentId);
        if (!departmentUsers.contains(sales)) {
            throw new RuntimeException("该销售不属于所选部门或其相关部门");
        }
        
        boolean exists = customer.getCustomerDepartments().stream()
            .anyMatch(cd -> cd.getDepartment().getId().equals(departmentId));
        
        if (exists) {
            throw new RuntimeException("该部门关联已存在");
        }
        
        CustomerDepartment customerDepartment = new CustomerDepartment();
        customerDepartment.setCustomer(customer);
        customerDepartment.setDepartment(department);
        customerDepartment.setSales(sales);
        
        customerDepartmentRepository.save(customerDepartment);
        
        // 记录添加部门日志
        Long currentUserId = SecurityUtils.getCurrentUserId();
        User operator = userService.getUserById(currentUserId);
        customerLogService.logDepartmentAdd(customer, operator, department, sales);
    }

    @Override
    public void deleteCustomerDepartment(Long customerId, Long departmentId) {
        Customer customer = customerRepository.findById(customerId)
            .orElseThrow(() -> new RuntimeException("Customer not found"));
        
        Department department = departmentRepository.findById(departmentId)
            .orElseThrow(() -> new RuntimeException("Department not found"));
 
        CustomerDepartmentId id = new CustomerDepartmentId();
        id.setCustomer(customerId);
        id.setDepartment(departmentId);
        
        customerDepartmentRepository.deleteById(id);
        
        // 记录移除部门日志
        Long currentUserId = SecurityUtils.getCurrentUserId();
        User operator = userService.getUserById(currentUserId);
        customerLogService.logDepartmentRemove(customer, operator, department);
    }

    @Override
    @Transactional
    public CustomerDTO approveCustomer(Long id, boolean approved, String comment) {
        Customer customer = customerRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + id));
        
        customer.setStatus(approved ? CustomerStatus.APPROVED : CustomerStatus.INACTIVE);
        customer.setComment(comment);
        customer.setUpdateAt(System.currentTimeMillis());
        customer.setUpdateUserId(SecurityUtils.getCurrentUserId());
        
        customer = customerRepository.save(customer);
        
        // 记录审批日志
        Long currentUserId = SecurityUtils.getCurrentUserId();
        User operator = userService.getUserById(currentUserId);
        if (approved) {
            customerLogService.logApprove(customer, operator, comment);
        } else {
            customerLogService.logReject(customer, operator, comment);
        }
        
        return convertToDTO(customer);
    }

    private CustomerDTO convertToDTO(Customer customer) {
        CustomerDTO dto = new CustomerDTO();
        BeanUtils.copyProperties(customer, dto);
        return dto;
    }


    private void updateCustomerFromDTO(Customer customer, CustomerDTO dto) {
        customer.setName(dto.getName());
        customer.setStage(dto.getStage());
        customer.setSource(dto.getSource());
        customer.setContactName(dto.getContactName());
        customer.setContactPhone(dto.getContactPhone());
        customer.setVisitAddress(dto.getVisitAddress());
        customer.setUpdateAt(System.currentTimeMillis());
        customer.setUpdateUserId(dto.getUpdateUserId());
        customer.setAddress(dto.getAddress());
        customer.setWebsite(dto.getWebsite());
        customer.setDescription(dto.getDescription());
        customer.setRemark(dto.getRemark());
        customer.setBusinessLicense(dto.getBusinessLicense());
        customer.setAnnualRevenue(dto.getAnnualRevenue());
        customer.setEmployeeCount(dto.getEmployeeCount());
        customer.setIndustryId(dto.getIndustryId());
        customer.setContactEmail(dto.getContactEmail());
        customer.setContactPosition(dto.getContactPosition());
        customer.setRegisterAddress(dto.getRegisterAddress());
    }

    @Override
    @Transactional(readOnly = true)
    public List<CustomerDTO> searchCustomers(String query) {
        if (query == null || query.trim().isEmpty()) {
            return Collections.emptyList();
        }
        
        String searchPattern = "%" + query.trim() + "%";
        List<Customer> customers;
        
        // 检查当前用户是否是管理员
        if (SecurityUtils.isAdmin()) {
            // 管理员可以查询所有客户
            customers = customerRepository.findByNameLikeIgnoreCase(searchPattern);
        } else {
            // 非管理员只能查询自己部门及子部门的客户
            User currentUser = SecurityUtils.getCurrentUser();
            if (currentUser == null || currentUser.getDepartmentId() == null) {
                return Collections.emptyList();
            }
            
            // 获取当前用户部门及其所有子部门的ID列表
            List<Department> departments = departmentService.getDepartmentAndChildren(currentUser.getDepartmentId());
            List<Long> departmentIds = departments.stream()
                .map(Department::getId)
                .collect(Collectors.toList());
            
            // 查询这些部门关联的客户
            customers = customerRepository.findByNameLikeIgnoreCaseAndDepartmentIds(searchPattern, departmentIds);
        }
        
        return customers.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }

    @Override
    public Customer findById(Long id) {
        return customerRepository.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + id));
    }
}
